﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using RH.Domain;
using RH.Web.ViewModels;
using AutoMapper;
using RH.Common.Xml;
using RH.Common.Extensions;
using RH.Common.DB;
using System.IO;
using RH.Common.Mail;
using System.Text;

using System.Web.Mvc;
using RH.Web.Utility;

namespace RH.Web.Utility
{
    public static class WebUtil
    {               
        public static String GetBooleanLabelID(String elementName, bool isEnabled)
        {
            if (isEnabled)
                return String.Format("{0}{1}_Yes", AppConstants.UI.DYNAMIC_CONTROL_PREFIX, elementName);
            else
                return String.Format("{0}{1}_No", AppConstants.UI.DYNAMIC_CONTROL_PREFIX, elementName);
        }
        
        /// <summary>
        /// Maps category definition to View Model
        /// </summary>
        /// <param name="productViewModel"></param>
        /// <param name="modelXml"></param>
        public static void MapZGL(ProductViewModel productViewModel, String modelXml)
        {
            ZGLModel model = XmlHelper.ToObject<ZGLModel>(modelXml);
            ///If Edit Mode of a Product
            if (!productViewModel.ZGLPayloadXml.IsNullOrEmpty())
            {
                ZGLPayload productDefinition = XmlHelper.ToObject<ZGLPayload>(productViewModel.ZGLPayloadXml);
                foreach (ZGLModelGroup group in model.Group)
                {
                    foreach (ZGLModelGroupProperty property in group.Property)
                    {
                        _SetPropertyValue(property, productDefinition.Property);
                    }
                }
            }
            productViewModel.ZGLModel = model;
        }

        private static void _SetPropertyValue(ZGLModelGroupProperty property, List<ZGLPayloadProperty> sourceProperties)
        {
            ZGLPayloadProperty sourceProperty = sourceProperties.FirstOrDefault(P => String.Compare(P.Name, property.Name, true) == 0);
            if (sourceProperty != null)
                property.Value = sourceProperty.Value;
        }
        /// <summary>
        /// Gets Formated Data for Display Purpose
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static String FormatData(object data)
        {
            if (data.GetType() == typeof(String))
                return NullHandler.GetString(data);
            else if (data.GetType() == typeof(DateTime))
                return NullHandler.GetDateTime(data).ToString(AppConstants.ValueOf.DATE_FROMAT_DISPLAY);
            else if (data.GetType() == typeof(decimal))
                return String.Format(AppConstants.ValueOf.DECIMAL_FORMAT, NullHandler.GetDecimal(data));
            else if (data.GetType() == typeof(bool))
                return NullHandler.GetBoolean(data) ? "Yes" : "No";
            else
                return NullHandler.GetString(data).IsEmpty() ? "N/A" : NullHandler.GetString(data);
        }

        /// <summary>
        /// HtmlEncodes text and replaces newline with <br/> tags to create newline in web pages
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public static String FormatText(String text)
        {
            return text.HtmlEncode().Replace(Environment.NewLine, "<br />").Replace("\n", "<br />");
        }
        /// <summary>
        /// Reads HTML Template from File System
        /// </summary>
        /// <param name="templateFileName"></param>
        /// <returns></returns>
        public static String ReadEmailTemplate(String templateFileName)
        {
            String filePath = HttpContext.Current.Server.MapPath(templateFileName);
            if (File.Exists(filePath))
                return File.ReadAllText(filePath);

            return String.Empty;
        }
        /// <summary>
        /// Gets Currently Hosted Domain Address
        /// </summary>
        /// <returns></returns>
        public static String GetDomainAddress()
        {
            Uri uri = HttpContext.Current.Request.Url;
            String url = String.Format("{0}{1}{2}{3}", uri.Scheme, Uri.SchemeDelimiter, uri.Host, uri.Port == 80 ? String.Empty : ":" + uri.Port);
            //return String.Format("http://{0}", HttpContext.Current.Request.Url.Host);
            return url;
        }

        /// <summary>
        /// Sends email, if fails to send then saves to database
        /// </summary>
        /// <param name="fromEmail"></param>
        /// <param name="toEmail"></param>
        /// <param name="bcc"></param>
        /// <param name="cc"></param>
        /// <param name="subject"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public static bool SendMail(String fromEmail, String toEmail, String bcc, String cc, String subject, String message)
        {
            bool isSent = false;
            try
            {
                if (ConfigReader.SendEmailThroughGmail)
                    isSent = MailManager.SendEmailThroughGmail(fromEmail, toEmail, subject, message);
                else
                    isSent = MailManager.SendMail(toEmail, cc, bcc, fromEmail, subject, message);
            }
            catch (Exception ex)
            {
                if (ConfigReader.LogErrorsInDb)
                {
                    ///Log Failed Message
                    AppEntities context = new AppEntities();
                    if (context.IsConnected())
                    {
                        EmailMessage email = new EmailMessage();
                        email.Subject = subject;
                        email.FromEmail = fromEmail;
                        email.ToEmail = toEmail;
                        email.CC = cc;
                        email.BCC = bcc;
                        email.Message = message;
                        email.IsSent = false;
                        email.Created = DateTime.Now;
                        email.AttemptedOn = DateTime.Now;
                        email.ErrorMessage = ex.Message;
                        email.StackTrace = ex.StackTrace;
                        if (SessionCache.CurrentUser != null)
                            email.UserID = SessionCache.CurrentUser.ID;
                        context.AddToEmailMessages(email);
                        context.SaveChanges();
                    }
                }
            }
            return isSent;
        }

        /// <summary>
        /// Gets default property value from a ZGLModel
        /// </summary>
        /// <param name="groupName"></param>
        /// <param name="propertyName"></param>
        /// <param name="product"></param>
        /// <returns></returns>
        public static String GetPropertyValue(String groupName, String propertyName, ZGLModel model)
        {
            if (model != null && model.Group != null)
            {
                ZGLModelGroup group = model.Group.FirstOrDefault(G => G.Name == groupName);
                if (group != null)
                {
                    ZGLModelGroupProperty property = group.Property.FirstOrDefault(P => P.Name == propertyName);
                    if (property != null)
                        return property.Value;
                }
            }
            return "N/A";
        }

        /// <summary>
        /// Checks Whether an Uploaded file is a Valid Image File Or Not
        /// </summary>
        /// <param name="httpPostedFile"></param>
        /// <returns></returns>
        public static bool IsValidImageFile(HttpPostedFileBase httpPostedFile)
        {
            if (httpPostedFile.ContentLength > 0)
            {
                string extension = Path.GetExtension(httpPostedFile.FileName);
                return IsValidImageFileExtension(extension);
            }
            return false;
        }
        /// <summary>
        /// Checks for a valid file extension for an image.
        /// </summary>
        /// <param name="extension"></param>
        /// <returns></returns>
        private static bool IsValidImageFileExtension(string extension)
        {
            if (String.Compare(extension, ".jpg", true) == 0)
                return true;
            else if (String.Compare(extension, ".jpeg", true) == 0)
                return true;
            else if (String.Compare(extension, ".gif", true) == 0)
                return true;
            else if (String.Compare(extension, ".png", true) == 0)
                return true;
            return false;
        }
        /// <summary>
        /// Builds Company URL Routes and Saves them into the Database if forced
        /// </summary>
        /// <param name="forceRebuild"></param>
        /// <returns></returns>
        public static String BuildCompanyUrlRoutes(bool forceRebuild)
        {
            AppEntities context = new AppEntities();
            if (!context.IsConnected())
                return "undefined";

            Configuration config = context.Configurations.FirstOrDefault(P => String.Compare(P.Name, ConfigReader.CompaniesUrlConfigurationKey, true) == 0);
            if (config == null){
                config = new Configuration();
                config.Name = ConfigReader.CompaniesUrlConfigurationKey;
                context.Configurations.AddObject(config);
            }
            if(config.Value.IsEmpty() || forceRebuild)
            {
                var companies = context.Companies;
                StringBuilder sb = new StringBuilder(10);
                foreach (Company company in companies)
                {                    
                    company.CompanyUrl = company.Name.ToSeoUrl();
                    if (sb.Length == 0)
                        sb.Append(company.CompanyUrl);
                    else
                        sb.AppendFormat("|{0}", company.CompanyUrl);
                }
                if (sb.Length == 0)
                    sb.Append("undefined");
                if (forceRebuild)
                {
                    config.Value = sb.ToString();
                    context.SaveChanges();
                }
                return sb.ToString();
            }
            return config.Value;
        }
        /// <summary>
        /// Builds Content URL Routes and Saves them into the Database if forced
        /// </summary>
        /// <param name="forceRebuild"></param>
        /// <returns></returns>
        public static String BuildContentUrlRoutes(bool forceRebuild)
        {
            AppEntities context = new AppEntities();
            if (!context.IsConnected())
                return "undefined";

            Configuration config = context.Configurations.FirstOrDefault(P => String.Compare(P.Name, ConfigReader.ContentsUrlConfigurationKey, true) == 0);
            if (config == null)
            {
                config = new Configuration();
                config.Name = ConfigReader.ContentsUrlConfigurationKey;
                context.Configurations.AddObject(config);
            }
            if (config.Value.IsEmpty() || forceRebuild)
            {
                var contents = context.Contents;
                StringBuilder sb = new StringBuilder(10);
                foreach (Content content in contents)
                {
                    content.Url = content.Title.ToSeoUrl();
                    if (sb.Length == 0)
                        sb.Append(content.Url);
                    else
                        sb.AppendFormat("|{0}", content.Url);
                }
                if (sb.Length == 0)
                    sb.Append("undefined");
                if (forceRebuild)
                {
                    config.Value = sb.ToString();
                    context.SaveChanges();
                }
                return sb.ToString();
            }
            return config.Value;
        }
        /// <summary>
        /// Gets the IP Address of the Requested Client
        /// </summary>
        /// <returns></returns>
        public static string GetRemoteIPAddress()
        {
            return HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
        }
        /// <summary>
        /// Gets the Session Key of currently executing request
        /// </summary>
        /// <returns></returns>
        public static string GetSessionKey()
        {
            if(HttpContext.Current.Session != null)
                return HttpContext.Current.Session.SessionID;
            return String.Empty;
        }
        /// <summary>
        /// FIXME: Probably will not require in RH.Com
        /// Insert blank company information at the time 
        /// fist fase company registration
        /// </summary>
        /// <returns></returns>
        public static int InsertBlankCompany(string companyName)
        {
            AppEntities _Context = new AppEntities();
            CompanyViewModel viewModel = new CompanyViewModel();
            viewModel.Address = new AddressViewModel();

            viewModel.Name = companyName;
            viewModel.IndustryTypeID = Utility.ConfigReader.IndustryTypeID;
            //viewModel.DistrictID = Utility.ConfigReader.DistrictID;
            viewModel.Address.ZipCode = "__UnKnown";
            //viewModel.Phone = "__UnKnown";
            viewModel.IsActive = false;

            Company entity = new Company();
            entity = Mapper.Map<CompanyViewModel, Company>(viewModel, entity);
            entity.Address = new Address();
            entity.Address = Mapper.Map<AddressViewModel, Address>(viewModel.Address, entity.Address);
            entity.Address.ModifiedBy = SessionCache.CurrentUser == null ? -1 : SessionCache.CurrentUser.ID;
            //entity.Address.ModifiedOn = DateTime.Now;
            //entity.Address.CreatedOn = DateTime.Now;
            
            //_Context.AddToAddresses(address);
            _Context.AddToCompanies(entity);
            entity.CreatedOn = DateTime.Now;
            entity.ModifiedOn = DateTime.Now;
            entity.ActivationKey = System.Guid.NewGuid().ToString(); //System.Guid.NewGuid();
            entity.CompanyUrl = entity.Name.ToSeoUrl();
            _Context.SaveChanges();


            return entity.ID;
        }

        /// <summary>
        /// Builds address HTML for display in serveral places of the site.
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public static String BuildAddressHtml(AddressViewModel address)
        {
            StringBuilder sb = new StringBuilder();
            if (address != null)
            {
                if (!address.StreetAddress.IsEmpty())
                    sb.AppendFormat("{0}<br/>", address.StreetAddress);
                if (address.LocationID > 0)
                {
                    sb.AppendFormat("{0}, {1}<br/>", address.Location.Name, address.Location.District.Name);
                }
                if (!address.IsMinimalView)
                {
                    if (!address.Email.IsEmpty())
                        sb.AppendFormat("Email: {0}<br/>", address.Email);
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// FIXME: As UserContact mapping table has been removed so this functionaly has been disabled. Probably will not require any more.
        /// Insert initial information for a contact
        /// </summary>
        /// <returns></returns>
        //public static int InsertInitialContact(string email, string firstName, string lastName, int companyID)
        //{
        //    AppEntities _Context = new AppEntities();
        //    //CompanyViewModel viewModel = new CompanyViewModel();
        //    ContactViewModel contactViewModel = new ContactViewModel();

        //    contactViewModel.LastName = lastName;
        //    contactViewModel.FirstName = firstName;
        //    contactViewModel.Gender = "M";
        //    contactViewModel.EmailPersonal = email;
        //    contactViewModel.ReligionID = Utility.ConfigReader.ReligionID;
        //    contactViewModel.IsActive = "true";
        //    contactViewModel.IsDeleted = "false";
        //    contactViewModel.CompanyID = companyID;


        //    Contact entity = new Contact();
        //    entity = Mapper.Map<ContactViewModel, Contact>(contactViewModel, entity);
        //    _Context.AddToContacts(entity);
        //    _Context.SaveChanges();


        //    return entity.ID;
        //}

        /// <summary>
        /// Gets a boolean value depending on the key of the querystring.
        /// Strings that will be evaluated to boolean True are as follows:
        /// <para>
        /// true, True, yes, Yes, y, Y, 1
        /// </para>
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool GetQueryStringBoolean(String key)
        {
            String value = HttpContext.Current.Request[key];
            return value.ToBoolean();
        }

        public static int GetQueryStringInt(String key)
        {
            String value = HttpContext.Current.Request[key];
            return value.ToInt();
        }

        public static String GetQueryStringValue(String key)
        {
            String value = HttpContext.Current.Request[key];
            return value;
        }
    }
}